package com.wowoai.chatai.service.impl;

import cn.hutool.core.io.FileUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.wowoai.chatai.controller.req.AIDrawingCallBackReq;
import com.wowoai.chatai.controller.req.GeneratePictureReq;
import com.wowoai.chatai.controller.req.UserDrawingRecordPageReqVO;
import com.wowoai.chatai.convert.UserDrawingConvert;
import com.wowoai.chatai.entity.UserDrawingEntity;
import com.wowoai.chatai.enums.ImageStatusEnum;
import com.wowoai.chatai.enums.MJLineEnum;
import com.wowoai.chatai.repository.UserDrawingRepositoryI;
import com.wowoai.chatai.service.AIServiceI;
import com.wowoai.chatai.service.dto.UserDrawingDTO;
import com.wowoai.chatai.service.dto.UserImageDTO;
import com.wowoai.common.basemodule.BusinessException;
import com.wowoai.common.enums.ResponseEnum;
import com.wowoai.common.factoy.OssClientFactory;
import com.wowoai.common.page.Pagination;
import com.wowoai.common.userInfo.UserInfo;
import com.wowoai.dialog.service.DialogServiceI;
import com.wowoai.dialog.service.dto.DialogHistoryDTO;
import com.wowoai.user.service.UserServiceI;
import com.wowoai.user.service.dto.UserDTO;
import com.wowoai.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.*;

@Service
@Slf4j
public class AIServiceImpl implements AIServiceI {

    private final OssClientFactory ossClientFactory;

    private final UserServiceI userServiceI;

    private final UserDrawingRepositoryI userDrawingRepositoryI;

    private final DialogServiceI dialogServiceI;

    public AIServiceImpl(OssClientFactory ossClientFactory, UserServiceI userServiceI, UserDrawingRepositoryI userDrawingRepositoryI, DialogServiceI dialogServiceI){

        Assert.notNull(ossClientFactory,"ossClientFactory 不能为空");
        Assert.notNull(userServiceI,"userServiceI 不能为空");
        Assert.notNull(userDrawingRepositoryI,"userDrawingRepositoryI 不能为空");
        Assert.notNull(dialogServiceI,"dialogServiceI 不能为空");

        this.ossClientFactory = ossClientFactory;
        this.userServiceI = userServiceI;
        this.userDrawingRepositoryI = userDrawingRepositoryI;
        this.dialogServiceI = dialogServiceI;
    }


    private static final String AI_DRAWING_PHAT = "ai_drawing";

    /**
     * 请求url
     */
    @Value("${zsy.mj.url}")
    private String zsyMJUrl;

    @Value("${zsy.mj.fast_url}")
    private String zsyMJFastUrl;

    @Value("${zsy.chat.url}")
    private String zsyChatUrl;

    /**
     * 保存的下载文件的本地临时地址
     */
    @Value("${local.file.path}")
    private String filePath;

    /**
     * MJ绘画的回调接口
     */
    @Value("${zsy.mj.callback_base_url}")
    private String callbackBaseUrl;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void aIDrawingHandle(Long userId, AIDrawingCallBackReq aiDrawingCallBackReq) {
        //处理请求
        if (Objects.nonNull(aiDrawingCallBackReq.getDetail())){
            //处理状态
            dialogServiceI.changeStatus(aiDrawingCallBackReq.getTask_id(), ImageStatusEnum.CREATE_FAIL);//更新状态
            throw new BusinessException(ResponseEnum.BUSINESS_FAIL.getCode(),aiDrawingCallBackReq.getDetail());
        }
        // 处理图片分4张
        // 查询用户
        UserDTO userDTO = userServiceI.getUserById(userId);
        String diskPath = filePath + File.separator + userId;
        try {
            String localFilePath = FileDownloadUtils.downLoadFromUrl(aiDrawingCallBackReq.getImage_url(), diskPath);
            List<File> files = FileUtils.splitImage(new File(localFilePath), 2, 2);
            log.info("分割之后的图片 = {}",JsonUtils.toJsonString(files));
            // 异步提交上传任务
            List<CompletableFuture<String>> futures = new ArrayList<>();
            for (File file : files) {
                CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                    try {
                        InputStream inputStream = Files.newInputStream(file.toPath());
                        MockMultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "APPLICATION_OCTET_STREAM", inputStream);
                        return ossClientFactory.upload(multipartFile, AI_DRAWING_PHAT, null);
                    } catch (IOException e) {
                        throw new RuntimeException("上传任务执行异常", e);
                    }
                });
                futures.add(future);
            }

            // 结果聚合
            CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
            allFutures.join();
            List<String> resultList = new ArrayList<>();
            log.info("执行的futures大小 = {}",futures.size());
            for (CompletableFuture<String> future : futures) {
                resultList.add(future.join());
            }
            // 保存数据到数据库
            List<UserDrawingEntity> entities = new ArrayList<>();
            //根据taskId查询描述语句
            DialogHistoryDTO dto = dialogServiceI.findByTaskId(aiDrawingCallBackReq.getTask_id());
            dialogServiceI.changeStatus(aiDrawingCallBackReq.getTask_id(), ImageStatusEnum.CREATE_SUCCESS);//更新状态
            log.info("得到绘画图片结果的大小 ={}",resultList.size());
            for (String fileUrl : resultList) {
                UserDrawingEntity entity = UserDrawingEntity.create(IdGeneratorUtil.nextId(), userDTO.getNickName(), userId, fileUrl, userDTO.getPhoneNumber(), aiDrawingCallBackReq.getTask_id(),Objects.nonNull(dto) ? dto.getProblem() : "");
                entities.add(entity);
            }
            userDrawingRepositoryI.saveAll(entities);

            // 上传完成清空文件夹
            CompletableFuture.runAsync(() -> FileUtil.clean(diskPath));
        } catch (IOException e) {
            throw new BusinessException("AI生成错误" + e.getMessage());
        }
    }

    @Override
    public Pagination<UserDrawingDTO> getDrawingImagePage(UserInfo userInfo, UserDrawingRecordPageReqVO reqVO) {
        Pagination<UserDrawingEntity> userDrawingEntityPagination = userDrawingRepositoryI.getDrawingImagePage(reqVO.getPageNum(), reqVO.getPageSize(), userInfo.getPhoneNumber());
        return userDrawingEntityPagination.map(UserDrawingConvert.INS::entity2DTO);
    }

    @Override
    public UserImageDTO getUserImageList(String phoneNumber, String taskId) {
        List<UserDrawingEntity> userDrawingEntityList = userDrawingRepositoryI.getUserImageList(phoneNumber, taskId);
        if (CollectionUtils.isEmpty(userDrawingEntityList)) {
            return null;
        }
        //业务封装
        List<String> images = new ArrayList<>();
        for (UserDrawingEntity userDrawingEntity : userDrawingEntityList) {
            images.add(userDrawingEntity.getImageUrl());
        }
        UserImageDTO userImageDTO = new UserImageDTO();
        userImageDTO.setImages(images);
        userImageDTO.setUserId(userDrawingEntityList.get(0).getUserId());
        userImageDTO.setTaskId(userDrawingEntityList.get(0).getTaskId());

        return userImageDTO;
    }

    /**
     * 发送图片生成请求
     *
     * @param userDTO            用户信息
     * @param generatePictureReq 生成图片的请求参数
     * @param promptCN           翻译之后的中文描述
     * @return 生成图片的taskId
     */
    @Override
    public String generatePicture(UserDTO userDTO, GeneratePictureReq generatePictureReq, String promptCN) {
        Map<String, Object> params = new HashMap<>();
        params.put("action", generatePictureReq.getAction());
        params.put("prompt", generatePictureReq.getPrompt());
        params.put("timeout", 1200);
        params.put("callback_url", callbackBaseUrl + userDTO.getId());

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        ArrayList<MediaType> acceptList = new ArrayList<>();
        acceptList.add(MediaType.APPLICATION_JSON);
        httpHeaders.setAccept(acceptList);
        log.info("生成图片发送请求参数 = {}", params);
        try {
            Map responseMap = null;
            if (Objects.equals(generatePictureReq.getLine(), MJLineEnum.SLOW_LINE.getCode())) {
                //慢速
                responseMap = HttpClientUtil.doPost(zsyMJUrl, params, httpHeaders);
            } else if (Objects.equals(generatePictureReq.getLine(), MJLineEnum.FAST_LINE.getCode())) {
                //快速
                responseMap = HttpClientUtil.doPost(zsyMJFastUrl, params, httpHeaders);
            }
            assert responseMap != null;
            String task_id = (String) responseMap.get("task_id");
            String detail = (String) responseMap.get("detail");
            if (Objects.nonNull(detail)) {
                throw new BusinessException(ResponseEnum.BUSINESS_FAIL.getCode(), detail);
            }
            //保存taskId的绘画描述
            dialogServiceI.saveDialogContentForMidJourney(userDTO,task_id,promptCN + " " + generatePictureReq.getDefine());
            return task_id;
        } catch (JsonProcessingException e) {
            throw new BusinessException(ResponseEnum.FAIL.getCode(), "生成照片发送失败" + e.getMessage());
        }
    }

    /**
     * ai翻译成英文将AI绘画的魔法
     * @param problem 问题
     * @return 响应的文本
     */
    @Override
    public String generateChat(String problem) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("question", problem);
        try {
            Map resultMap = HttpClientUtil.doPost(zsyChatUrl, requestBody, httpHeaders);
            String answer = (String) resultMap.get("answer");
            return answer;
        } catch (JsonProcessingException e) {
            throw new BusinessException("AI绘画失败");
        }
    }
}
